<?php

namespace Hilaoyu\ComputeCloudClient\Api;

use Hilaoyu\ComputeCloudClient\AssetModel;
use Hilaoyu\ComputeCloudClient\AssetModels;
use Hilaoyu\ComputeCloudClient\Interfaces\ApiVpcInterface;
use Hilaoyu\Utils\UtilArr;
use Hilaoyu\Utils\UtilStr;
use HuaweiCloud\SDK\Core\Exceptions\ClientRequestException;
use HuaweiCloud\SDK\Core\Exceptions\ServiceResponseException;
use HuaweiCloud\SDK\Ecs\V2\Model\ShowServerRequest;
use HuaweiCloud\SDK\Eip\V2\Model\CreatePublicipBandwidthOption;
use HuaweiCloud\SDK\Eip\V2\Model\CreatePublicipOption;
use HuaweiCloud\SDK\Eip\V2\Model\CreatePublicipRequest;
use HuaweiCloud\SDK\Eip\V2\Model\CreatePublicipRequestBody;
use HuaweiCloud\SDK\Eip\V2\Model\DeletePublicipRequest;
use HuaweiCloud\SDK\Eip\V2\Model\ListPublicipsRequest;
use HuaweiCloud\SDK\Eip\V2\Model\UpdatePublicipOption;
use HuaweiCloud\SDK\Eip\V2\Model\UpdatePublicipRequest;
use HuaweiCloud\SDK\Eip\V2\Model\UpdatePublicipsRequestBody;
use HuaweiCloud\SDK\Vpc\V2\Model\AsscoiateReq;
use HuaweiCloud\SDK\Vpc\V2\Model\AssociateRouteTableAndSubnetReq;
use HuaweiCloud\SDK\Vpc\V2\Model\AssociateRouteTableRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateRouteTableReq;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateRoutetableReqBody;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateRouteTableRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateSubnetOption;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateSubnetRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateSubnetRequestBody;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateVpcOption;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateVpcRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\CreateVpcRequestBody;
use HuaweiCloud\SDK\Vpc\V2\Model\DeleteRouteTableRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\DeleteSubnetRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\DeleteVpcRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\ListRouteTablesRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\ListSubnetsRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\RoutetableAssociateReqbody;
use HuaweiCloud\SDK\Vpc\V2\Model\RouteTableRoute;
use HuaweiCloud\SDK\Vpc\V2\Model\ShowPortRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\ShowRouteTableRequest;
use HuaweiCloud\SDK\Vpc\V2\Model\UpdateRouteTableReq;
use HuaweiCloud\SDK\Vpc\V2\Model\UpdateRoutetableReqBody;
use HuaweiCloud\SDK\Vpc\V2\Model\UpdateRouteTableRequest;
use HuaweiCloud\SDK\Vpc\V3\Model\ListVpcsRequest;

/**
 * Class HuaWeiVpc
 * @package Hilaoyu\ComputeCloudClient\Api
 * @property   $cliepnt
 */
class HuaWeiVpc extends HuaWeiApiBase implements ApiVpcInterface
{

    public function vpcsDescribe(string $vpcId = null, string $vpcname = null, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $request = new ListVpcsRequest([
                'id' => $vpcId ? (array)$vpcId : null,
                'name' => $vpcname ? (array)$vpcname : null,
            ]);

            $result = $this->clientVpcV3()->listVpcs($request);

            $data = (array)$result->getVpcs();


            foreach ($data as $datum) {
                $id = $datum->getId();
                if (!$id) {
                    continue;
                }

                $model = new AssetModel();
                $model->type = 'vpc';
                $model->asset_id = $id;
                $model->region_id = $regionId;
                $model->name = $datum->getName();
                $model->network = $datum->getCidr();
                $model->status = $datum->getStatus();
                $model->status = $this->formatStatus('vpc',$model->status);


                $models->push($model);
            }

        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return $models;
    }

    public function vpcDescribe(string $vpcId, $regionId = ''): ?AssetModel
    {
        $models = $this->vpcsDescribe($vpcId, null, $regionId);
        if (!$models) {
            return null;
        }

        return $models->first(function ($item) use ($vpcId) {
            return $item->asset_id == $vpcId;
        });
    }

    public function vpcCreate($vpcname = null, $network = null, $ipv6Network = null, $regionId = '', $resourceGroupId = null): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        try {
            if ($vpcname) {
                $hasVpcs = $this->vpcsDescribe($vpcname, $regionId);

                if ($hasVpcs && $hasVpcs->count() > 0) {
                    throw new \Exception('vpcname is exists');
                }
            }
            $request = new CreateVpcRequest([
                'body' => [
                    'vpc' => [
                        'name' => $vpcname,
                        'cidr' => $network,
                    ]
                ]
            ]);
            $result = $this->clientVpcV2()->createVpc($request);

            $datum = $result->getVpc();
            $id = $datum->getId();
            if (!$id) {
                throw new \Exception('返回数据错误');
            }

            $model = new AssetModel();
            $model->type = 'vpc';
            $model->asset_id = $id;
            $model->region_id = (string)$regionId;
            $model->name = $datum->getName();
            $model->network = $datum->getCidr();
            $model->status = 'Pending';
            return $model;
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }

        return null;
    }

    public function vpcDelete($vpcId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $vpcId = trim($vpcId);
        if (!$vpcId) {
            return false;
        }
        if (!$this->vpcDescribe($vpcId)) {
            return true;
        }

        try {
            $request = new DeleteVpcRequest([
                'vpcId' => $vpcId,
            ]);
            $result = $this->clientVpcV2()->deleteVpc($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;
    }

    public function vSwitchCreate($vpcId, $zoneId, $network, $vSwitchName = null, $ipv6Network = null, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        $zoneId = trim($zoneId);
        $vpcId = trim($vpcId);
        $vSwitchName = trim($vSwitchName);
        if (!$vSwitchName) {
            $vSwitchName = UtilStr::randString(8);
        }

        if (!$vpcId) {
            return null;
        }
        try {
            $request = new CreateSubnetRequest([]);

            $body = new CreateSubnetRequestBody();
            $subnetbody = new CreateSubnetOption();
            $subnetbody->setName($vSwitchName)
                ->setCidr($network)
                ->setGatewayIp($this->api::GetGateWay($network))
                ->setDnsList($this->privateNameServersDescribe())
                ->setAvailabilityZone($zoneId)
                ->setDhcpEnable(true)
                ->setIpv6Enable(false)
                ->setVpcId($vpcId);
            $body->setSubnet($subnetbody);
            $request->setBody($body);

            $result = $this->clientVpcV2()->createSubnet($request);

            $datum = $result->getSubnet();
            //dump($result,$datum);
            $id = $datum->getId();
            if (!$id) {
                throw new \Exception('返回数据错误');
            }

            $model = new AssetModel();
            $model->type = 'vsw';
            $model->asset_id = $id;
            $model->region_id = (string)$regionId;
            $model->name = $datum->getName();
            $model->network = $datum->getCidr();
            $model->bind_asset_id = (string)$vpcId;
            $model->status = 'Pending';
            return $model;
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return null;
    }

    public function vSwitchDelete($vSwitchId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $vSwitchId = trim($vSwitchId);

        if (!$vSwitchId) {
            return false;
        }
        $vSwitch = $this->vSwitchDescribe($vSwitchId);
        if (!$vSwitch) {
            return true;
        }
        try {
            $request = new DeleteSubnetRequest([
                'vpcId' => $vSwitch->bind_asset_id,
                'subnetId' => $vSwitchId,
            ]);
            $result = $this->clientVpcV2()->deleteSubnet($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;

    }

    public function vSwitchsDescribe($vSwitchId = null, $vSwitchName = null, $vpcId = null, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $request = new ListSubnetsRequest([
                'vpcId' => $vpcId,
            ]);
            $result = $this->clientVpcV2()->listSubnets($request);

            $data = (array)$result->getSubnets();

            foreach ($data as $datum) {
                $id = $datum->getId();
                if (!$id) {
                    continue;
                }

                $model = new AssetModel();
                $model->type = 'vsw';
                $model->asset_id = $id;
                $model->region_id = (string)$regionId;
                $model->name = $datum->getName();
                $model->bind_asset_id = $datum->getVpcId();
                $model->network = $datum->getCidr();
                $model->status = $datum->getStatus();
                $model->status = $this->formatStatus('vsw',$model->status);
                $model->vsw_vtb = "";


                $models->push($model);
            }

        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return $models;
    }

    public function vSwitchDescribe($vSwitchId, $regionId = ''): ?AssetModel
    {
        $models = $this->vSwitchsDescribe($vSwitchId, null, null, $regionId);
        if (!$models) {
            return null;
        }

        return $models->first(function ($item) use ($vSwitchId) {
            return $item->asset_id == $vSwitchId;
        });

    }



    //EIP

    /**
     * @param int $bandwidth EIP的带宽峰值，取值范围：1~200，单位为Mbps
     * @param string $instanceChargeType EIP的计费方式，取值： PrePaid：包年包月。 PostPaid（默认值）：按量计费。; 当InstanceChargeType取值为PrePaid时，InternetChargeType必须取值PayByBandwidth；当InstanceChargeType取值为PostPaid时，InternetChargeType可取值PayByBandwidth或PayByTraffic
     * @param string $internetChargeType EIP的计量方式，取值： PayByBandwidth（默认值）：按带宽计费。 PayByTraffic：按流量计费。; 当InstanceChargeType取值为PrePaid时，InternetChargeType必须取值PayByBandwidth。;当InstanceChargeType取值为PostPaid时，InternetChargeType可取值PayByBandwidth或PayByTraffic。
     * @param string $isp 线路类型 BGP：BGP（多线）线路。BGP_PRO：BGP（多线）精品线路
     * @param string $pricingCycle 包年包月的计费周期，取值：Month（默认值）：按月付费。Year：按年付费;当InstanceChargeType参数的值为PrePaid时，该参数必选；当InstanceChargeType参数的值为PostPaid时，该参数可不填
     * @param int $period 购买时长。 当PricingCycle取值Month时，Period取值范围为1~9。  当PricingCycle取值Year时，Period取值范围为1~5。  如果InstanceChargeType参数的值为PrePaid时，该参数必选，如果InstanceChargeType参数的值为PostPaid时，该参数不填。
     * @param string $regionId
     * @param null $resourceGroupId 资源组ID
     * @return AssetModel
     */
    public function eipAddressAllocate(int $bandwidth = 50, string $instanceChargeType = 'PostPaid', string $internetChargeType = 'PayByTraffic', string $isp = 'BGP', string $pricingCycle = '', int $period = null, string $name = null, $regionId = '', $resourceGroupId = null): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        $bandwidth = intval($bandwidth);
        try {
            /*[
                'regionId' => $regionId,
                //'bandwidth' => $bandwidth,
                'pricingCycle' => $pricingCycle,
                'period' => $period,
                'instanceChargeType' => $instanceChargeType,
                //'internetChargeType' => $internetChargeType,
                //'ISP' => $isp,
                'name' => $name,
            ]*/
            $request = (new CreatePublicipRequest())
                ->setBody(
                    (new CreatePublicipRequestBody())
                        ->setPublicip(
                            (new CreatePublicipOption())
                                ->setType($this->getPublicIpType($regionId))
                                ->setIpVersion(4)
                            ->setAlias($name)
                        )
                        ->setBandwidth(
                            (new CreatePublicipBandwidthOption())
                                ->setShareType("PER")
                                ->setSize($bandwidth)
                                ->setName($name)
                                ->setChargeMode($this->formatEipChargeType($internetChargeType))
                        )
                );
            $result = $this->clientEip()->createPublicip($request);


            $datum = $result->getPublicip();
            $id = $datum->getId();
            if (!$id) {
                throw new \Exception('返回数据错误');
            }

            $model = new AssetModel();
            $model->type = 'eip';
            $model->asset_id = $id;
            $model->region_id = (string)$regionId;
            $model->primary_ip = $datum->getPublicIpAddress();
            $model->name = $model->primary_ip;
            $model->bandwidth = $bandwidth;
            $model->instance_type = $isp;
            $model->status = 'Pending';
            return $model;
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return null;
    }

    public function eipAddressUpdate(string $allocationId,string $name=null,int $bandwidth=50,$regionId = ''):?AssetModel{
        $regionId = $this->getRegionId($regionId);
        $name = trim($name);
        $bandwidth = intval($bandwidth);
        try {
            if (!$model = $this->eipAddressDescribe($allocationId,null, $regionId)) {
                throw new \Exception('eip不存在');
            }

            if(!$name ){
                return $model;
            }

            $request = new UpdatePublicipRequest();
            $request->setPublicipId($allocationId);

            $body = new UpdatePublicipsRequestBody();
            $publicipbody = new UpdatePublicipOption();
            $publicipbody->setAlias($name);
            $body->setPublicip($publicipbody);
            $request->setBody($body);


            $result = $this->clientEip()->updatePublicip($request);

            if(!(bool)$result->valid()){
                throw new \Exception('返回数据错误');
            }

            /*if($bandwidth > 0 ){
                $model->bandwidth = $bandwidth;
            }*/
            if($name ){
                $model->name = $name;
            }
            return $model;
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return null;
    }

    public function eipAddressRelease(string $allocationId, $regionId = ''): bool
    {
        if (!$this->eipAddressDescribe($allocationId,null, $regionId)) {
            return true;
        }
        $regionId = $this->getRegionId($regionId);
        try {
            $request = new DeletePublicipRequest([
                'publicipId' => $allocationId,
            ]);
            $result = $this->clientEip()->deletePublicip($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;
    }

    public function eipAddressAssociate(string $allocationId, string $instanceId, string $instanceType = null, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);


        try {
            $request = new UpdatePublicipRequest([
                'publicipId' => $allocationId,
            ]);
            $publicipOption = new UpdatePublicipOption();
            if ($instanceId) {
                $ecs_request = (new ShowServerRequest())->setServerId($instanceId);

                $ecs_result = $this->clientEcs()->showServer($ecs_request);

                $ecsServer = $ecs_result->getServer();
                $ipAddresses = UtilArr::collapse($ecsServer->getAddresses());

                $primaryAddress =  UtilArr::first($ipAddresses, function ($item) {
                    return 'fixed' == $item->getOsExtIpStype();
                });
                if (!$primaryAddress) {
                    throw new \Exception("没有找到对应的网卡");
                }

                $publicipOption->setPortId($primaryAddress->getOsExtIpSportId());
            }

            $request->setBody(
                (new UpdatePublicipsRequestBody())
                    ->setPublicip(
                        $publicipOption
                    )
            );

            $result = $this->clientEip()->updatePublicip($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;
    }

    public function eipAddressUnassociate(string $allocationId, string $instanceId = null, $regionId = ''): bool
    {
        return $this->eipAddressAssociate($allocationId, "", null, $regionId);
    }


    public function eipAddressesDescribe(string $allocationId = null, string $eipAddress = null, string $status = null, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $request = new ListPublicipsRequest([
                'id' => $allocationId ? (array)$allocationId : null,
                'publicIpAddress' => $eipAddress ? array($eipAddress) : null,
                //'status' => $status,
            ]);
            $result = $this->clientEip()->listPublicips($request);

            $data = (array)$result->getPublicips();



            foreach ($data as $datum) {
                $id = $datum->getId();
                if (!$id) {
                    continue;
                }

                $model = new AssetModel();
                $model->type = 'eip';
                $model->asset_id = $id;
                $model->region_id = (string)$regionId;
                $model->primary_ip = $datum->getPublicipAddress();
                $model->name = $model->primary_ip;
                $model->bind_asset_id = '';
                if($portId = $datum->getPortId()){
                    $portRequest = (new ShowPortRequest())->setPortId($portId);
                    $portResult = $this->clientVpcV2()->showPort($portRequest);
                    $port = $portResult->getPort();
                    if($port){
                        $model->bind_asset_id = $port->getDeviceId();
                    }

                }


                $model->os_type = 'eni';
                $model->instance_type = $this->formatIsp($datum->getType(), true);
                $model->bandwidth = $datum->getBandwidthSize();
                $model->status = $datum->getStatus();
                $model->status = $this->formatStatus('eip',$model->status);
                $models->push($model);
            }

        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return $models;
    }

    public function eipAddressDescribe(string $allocationId, string $eipAddress = null, $regionId = ''): ?AssetModel
    {
        $models = $this->eipAddressesDescribe($allocationId, $eipAddress, null, $regionId);
        if (!$models) {
            return null;
        }

        return $models->first(function ($item) use ($allocationId,$eipAddress) {
            return $item->asset_id == $allocationId || $item->primary_ip == $eipAddress;
        });

    }


    //路由表
    public function routeTableCreate($vpcId, $routeTableName = null, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        $vpcId = trim($vpcId);
        $routeTableName = trim($routeTableName);
        if(!$routeTableName){
            $routeTableName = UtilStr::randString(8);
        }

        if (!$vpcId) {
            return null;
        }
        try {
            $request = (new CreateRouteTableRequest())
                ->setBody(
                    (new CreateRoutetableReqBody())
                        ->setRoutetable(
                            (new CreateRouteTableReq())
                                ->setVpcId($vpcId)
                                ->setName($routeTableName)
                        )
                );
            $result = $this->clientVpcV2()->createRouteTable($request);

            $datum = $result->getRoutetable();
            $id = $datum->getId();
            if (!$id) {
                throw new \Exception('返回数据错误');
            }

            $model = new AssetModel();
            $model->type = 'vtb';
            $model->asset_id = $id;
            $model->region_id = (string)$regionId;
            $model->name = (string)$routeTableName;

            $model->os_type = 'Custom';
            $model->status = 'Pending';
            return $model;
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return null;
    }

    public function routeTableDelete($routeTableId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $routeTableId = trim($routeTableId);

        if (!$routeTableId) {
            return false;
        }

        if (!$this->routeTableDescribe($routeTableId)) {
            return true;
        }
        try {
            $request = (new DeleteRouteTableRequest())
                ->setRoutetableId($routeTableId);
            $result = $this->clientVpcV2()->deleteRouteTable($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;
    }

    public function routeTablesDescribe(string $routeTableId = null, string $vpcId = null, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $request = (new ListRouteTablesRequest());
            if ($routeTableId) {
                $request->setId($routeTableId);
            }
            if ($vpcId) {
                $request->setVpcId($vpcId);
            }
            $result = $this->clientVpcV2()->listRouteTables($request);

            $data = (array)$result->getRoutetables();

            foreach ($data as $datum) {
                $id = $datum->getId();
                if (!$id) {
                    continue;
                }

                $model = new AssetModel();
                $model->type = 'vtb';
                $model->asset_id = $id;
                $model->region_id = (string)$regionId;
                $model->name = $datum->getName();
                $model->os_type = $datum->getDefault() ? 'System' : 'Custom';
                $vswIds = $datum->getSubnets();
                $model->status = 'Available'.(empty($vswIds) ? 'NotUse' : 'InUse');
                $models->push($model);
            }

        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return $models;
    }

    public function routeTableDescribe(string $routeTableId, $regionId = ''): ?AssetModel
    {
        $models = $this->routeTablesDescribe($routeTableId, null, $regionId);
        if (!$models) {
            return null;
        }

        return $models->first(function ($item) use ($routeTableId) {
            return $item->asset_id == $routeTableId;
        });

    }

    public function routeTableAssociate(string $routeTableId, string $vSwitchId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $routeTableId = trim($routeTableId);
        $vSwitchId = trim($vSwitchId);
        if (!$routeTableId || !$vSwitchId) {
            return false;
        }
        try {
            $request = (new AssociateRouteTableRequest())
                ->setRoutetableId($routeTableId)
                ->setBody(
                    (new RoutetableAssociateReqbody())
                        ->setRoutetable(
                            (new AsscoiateReq())
                                ->setSubnets(
                                    (new AssociateRouteTableAndSubnetReq())
                                        ->setAssociate([$vSwitchId])
                                )

                        )
                );
            $result = $this->clientVpcV2()->associateRouteTable($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;
    }

    public function routeTableUnAssociate(string $routeTableId, string $vSwitchId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $routeTableId = trim($routeTableId);
        $vSwitchId = trim($vSwitchId);
        if (!$routeTableId || !$vSwitchId) {
            return false;
        }
        try {
            $request = (new AssociateRouteTableRequest())
                ->setRoutetableId($routeTableId)
                ->setBody(
                    (new RoutetableAssociateReqbody())
                        ->setRoutetable(
                            (new AsscoiateReq())
                                ->setSubnets(
                                    (new AssociateRouteTableAndSubnetReq())
                                        ->setDisassociate([$vSwitchId])
                                )

                        )
                );
            $result = $this->clientVpcV2()->disassociateRouteTable($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;
    }

    public function routeEntryCreate(string $routeTableId, string $destinationNetwork, string $nextHopId, $nextHopType = 'Instance', $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $routeTableId = trim($routeTableId);
        $destinationNetwork = trim($destinationNetwork);
        $nextHopId = trim($nextHopId);
        $nextHopType = trim($nextHopType);
        if (!$routeTableId || !$destinationNetwork || !$nextHopId) {
            return false;
        }
        try {
            $request = (new UpdateRouteTableRequest())
                ->setRoutetableId($routeTableId)
                ->setBody(
                    (new UpdateRoutetableReqBody())
                        ->setRoutetable(
                            (new UpdateRouteTableReq())
                                ->setRoutes(
                                    [
                                        'add' => [
                                            (new RouteTableRoute())
                                            ->setType($this->formatnextHopType($nextHopType))
                                            ->setDestination($destinationNetwork)
                                            ->setNexthop($nextHopId),
                                            ],
                                    ]
                                )
                        )
                );
            $result = $this->clientVpcV2()->updateRouteTable($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;
    }

    public function routeEntryDelete(string $routeTableId, string $destinationNetwork = null, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $routeTableId = trim($routeTableId);
        if (!$routeTableId) {
            return false;
        }
        try {
            $request = (new UpdateRouteTableRequest())
                ->setRoutetableId($routeTableId)
                ->setBody(
                    (new UpdateRoutetableReqBody())
                        ->setRoutetable(
                            (new UpdateRouteTableReq())
                                ->setRoutes(
                                    [
                                        'del' => [
                                            (new RouteTableRoute())
                                            ->setDestination($destinationNetwork),
                                            ],
                                    ]
                                )
                        )
                );
            $result = $this->clientVpcV2()->updateRouteTable($request);

            return (bool)$result->valid();
        } catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return false;
    }

    public function routeEntryListDescribe(string $routeTableId, $regionId = ''): array
    {
        $regionId = $this->getRegionId($regionId);
        $routeTableId = trim($routeTableId);
        if (!$routeTableId) {
            return [];
        }
        $models = [];
        try {
            $request = (new ShowRouteTableRequest())
            ->setRoutetableId($routeTableId)
            ;
            $result = $this->clientVpcV2()->showRouteTable($request);

            $data = $result->getRoutetable()->getRoutes();

            //dd($data);
            foreach ($data as $datum) {
                $id = $datum->getDestination();
                if (!$id) {
                    continue;
                }
                $models[] = ["id" => $id, "destination_network" => $id];
            }

        }catch (ServiceResponseException $exception) {
            $this->setError( $exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError( $exception->getMessage());
        }
        return $models;
    }


    protected function formatIsp($isp, $flip = false)
    {
        $arr = [
            'BGP_PRO' => '5_sbgp',
            'BGP' => '5_bgp',
        ];
        if ($flip) {
            $arr = array_flip($arr);
        }

        return UtilArr::get($arr, $isp, '');
    }

    protected function formatEipChargeType($type, $flip = false)
    {
        $arr = [
            'PayByBandwidth' => 'bandwidth',
            'PayByTraffic' => 'traffic',
        ];

        if ($flip) {
            $arr = array_flip($arr);
        }
        return UtilArr::get($arr, $type, '');
    }

    protected function formatnextHopType($type, $flip = false)
    {
        $arr = [
            'Instance' => 'ecs',
            'NetworkInterface' => 'eni',
            'HaVip' => 'vip',
            'NatGateway' => 'nat',
        ];

        if ($flip) {
            $arr = array_flip($arr);
        }
        return UtilArr::get($arr, $type, '');
    }
}
